#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <assert.h>

#include "arcsoft_fsdk_face_detection.h"

#include "merror.h"
#include <opencv2/opencv.hpp>

#define APPID     "your app id"
#define SDKKEY    "your sdk key"


#define INPUT_IMAGE_FORMAT  ASVL_PAF_RGB24_B8G8R8
#define INPUT_IMAGE_PATH    "your_input_image.yuv"
#define INPUT_IMAGE_WIDTH   (640)
#define INPUT_IMAGE_HEIGHT  (480)

#define WORKBUF_SIZE        (40*1024*1024)
#define MAX_FACE_NUM        (50)

int main(int argc, char* argv[]) {
    CvCapture* cam0 = cvCaptureFromCAM(0);
    if(!cam0) {
        fprintf(stderr, "Could not initialize opening of Camera 0..\n");
        system("Pause");
        return -1;
    }

    MByte *pWorkMem = (MByte *)malloc(WORKBUF_SIZE);
    if(pWorkMem == nullptr){
        fprintf(stderr, "fail to malloc workbuf\r\n");
        exit(0);
    }

    MHandle hEngine = nullptr;
    
    int ret = AFD_FSDK_InitialFaceEngine(APPID, SDKKEY, pWorkMem, WORKBUF_SIZE, 
                                         &hEngine, AFD_FSDK_OPF_0_HIGHER_EXT, 16, MAX_FACE_NUM);
    if (ret != 0) {
        fprintf(stderr, "fail to AFD_FSDK_InitialFaceEngine(): 0x%x\r\n", ret);
        free(pWorkMem);
        exit(0);
    }

    const AFD_FSDK_Version*pVersionInfo = AFD_FSDK_GetVersion(hEngine);
    printf("%d %d %d %d\r\n", pVersionInfo->lCodebase, pVersionInfo->lMajor,
                                 pVersionInfo->lMinor, pVersionInfo->lBuild);
    printf("%s\r\n", pVersionInfo->Version);
    printf("%s\r\n", pVersionInfo->BuildDate);
    printf("%s\r\n", pVersionInfo->CopyRight);

    cvNamedWindow("Camera 0",CV_WINDOW_AUTOSIZE); //create a window called "Camera 0"

    while(1) {

        IplImage *cam0Frame = cvQueryFrame(cam0);

        ASVLOFFSCREEN inputImg = { 0 };
        inputImg.u32PixelArrayFormat = INPUT_IMAGE_FORMAT;
        inputImg.i32Width = cam0Frame->width;
        inputImg.i32Height = cam0Frame->height;
        inputImg.ppu8Plane[0] = (MUInt8*)&cam0Frame->imageData[0];

        if (ASVL_PAF_I420 == inputImg.u32PixelArrayFormat) {
            inputImg.pi32Pitch[0] = inputImg.i32Width;
            inputImg.pi32Pitch[1] = inputImg.i32Width/2;
            inputImg.pi32Pitch[2] = inputImg.i32Width/2;
            inputImg.ppu8Plane[1] = inputImg.ppu8Plane[0] + inputImg.pi32Pitch[0] * inputImg.i32Height;
            inputImg.ppu8Plane[2] = inputImg.ppu8Plane[1] + inputImg.pi32Pitch[1] * inputImg.i32Height/2;
        } else if (ASVL_PAF_NV12 == inputImg.u32PixelArrayFormat) {
            inputImg.pi32Pitch[0] = inputImg.i32Width;
            inputImg.pi32Pitch[1] = inputImg.i32Width;
            inputImg.ppu8Plane[1] = inputImg.ppu8Plane[0] + (inputImg.pi32Pitch[0] * inputImg.i32Height);
        } else if (ASVL_PAF_NV21 == inputImg.u32PixelArrayFormat) {
            inputImg.pi32Pitch[0] = inputImg.i32Width;
            inputImg.pi32Pitch[1] = inputImg.i32Width;
            inputImg.ppu8Plane[1] = inputImg.ppu8Plane[0] + (inputImg.pi32Pitch[0] * inputImg.i32Height);
        } else if (ASVL_PAF_YUYV == inputImg.u32PixelArrayFormat) {
            inputImg.pi32Pitch[0] = inputImg.i32Width*2;
        } else if (ASVL_PAF_I422H == inputImg.u32PixelArrayFormat) {
            inputImg.pi32Pitch[0] = inputImg.i32Width;
            inputImg.pi32Pitch[1] = inputImg.i32Width / 2;
            inputImg.pi32Pitch[2] = inputImg.i32Width / 2;
            inputImg.ppu8Plane[1] = inputImg.ppu8Plane[0] + inputImg.pi32Pitch[0] * inputImg.i32Height;
            inputImg.ppu8Plane[2] = inputImg.ppu8Plane[1] + inputImg.pi32Pitch[1] * inputImg.i32Height;
        } else if (ASVL_PAF_LPI422H == inputImg.u32PixelArrayFormat) {
            inputImg.pi32Pitch[0] = inputImg.i32Width;
            inputImg.pi32Pitch[1] = inputImg.i32Width;
            inputImg.ppu8Plane[1] = inputImg.ppu8Plane[0] + (inputImg.pi32Pitch[0] * inputImg.i32Height);
        } else if (ASVL_PAF_RGB24_B8G8R8 == inputImg.u32PixelArrayFormat) {
            inputImg.pi32Pitch[0] = inputImg.i32Width*3;
        } else {
            fprintf(stderr, "unsupported Image format: 0x%x\r\n",inputImg.u32PixelArrayFormat);
            free(inputImg.ppu8Plane[0]);
            AFD_FSDK_UninitialFaceEngine(hEngine);
            free(pWorkMem);
            exit(0);
        }
        LPAFD_FSDK_FACERES faceResult;
        ret = AFD_FSDK_StillImageFaceDetection(hEngine, &inputImg, &faceResult);
        if (ret != 0) {
            fprintf(stderr, "fail to AFD_FSDK_StillImageFaceDetection(): 0x%x\r\n", ret);
            free(inputImg.ppu8Plane[0]);
            AFD_FSDK_UninitialFaceEngine(hEngine);
            free(pWorkMem);
            exit(0);
        }

        for (int i = 0; i < faceResult->nFace; i++) {
            printf("face %d:(%d,%d,%d,%d)\r\n", i, 
                faceResult->rcFace[i].left, faceResult->rcFace[i].top,
                faceResult->rcFace[i].right, faceResult->rcFace[i].bottom);
            cvRectangle(cam0Frame, cvPoint(faceResult->rcFace[i].left, faceResult->rcFace[i].top), 
                cvPoint(faceResult->rcFace[i].right, faceResult->rcFace[i].bottom),
                cvScalar(255, 0, 0), 2);
        }
        if (cam0Frame) {
            cvShowImage("Camera 0", cam0Frame);
        }
        if (cvWaitKey(30) > 0) //wait for 'Esc' key press for 30ms. If 'Esc' key is pressed, break loop
        {
            // cout << "Esc key is pressed by user" << endl;
            break;
        }
    }
    // free(inputImg.ppu8Plane[0]);

    cvReleaseCapture(&cam0);
	AFD_FSDK_UninitialFaceEngine(hEngine);
    free(pWorkMem);

    return 0;
}
